package dk.hewison.util;


import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

/**
 * This class creates thumbnails from bigger images. Useful to have a
 * preview of a photo for example.
 */

public class Thumbnail {

    /**
     * Create a reduced jpeg version of an image. The width/height
     * ratio is preserved.
     *
     * @param data        raw data of the image
     * @param thumbWidth  maximum width of the reduced image
     * @param thumbHeight maximum heigth of the reduced image
     * @param quality     jpeg quality of the reduced image
     * @return a reduced jpeg image if the image represented by data is
     *         bigger than the maximum dimensions of the reduced image,
     *         otherwise data is returned
     */
    public static byte[] createThumbArray(byte[] data,
                                          int thumbWidth, int thumbHeight,
                                          int quality)
            throws Exception {
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        createThumb(data, thumbWidth, thumbHeight, quality, result);
        return result.toByteArray();
    }

    public static void createThumb(File imageFile, int thumbWidth, int thumbHeight, int quality, File outputFile) throws Exception {
        FileOutputStream fos = new FileOutputStream(outputFile);
        createThumb(getBytesFromFile(imageFile), thumbWidth, thumbHeight, quality, fos);
    }

    /**
     * Create a reduced jpeg version of an image. The width/height
     * ratio is preserved.
     *
     * @param data        raw data of the image
     * @param thumbWidth  maximum width of the reduced image
     * @param thumbHeight maximum heigth of the reduced image
     * @param quality     jpeg quality of the reduced image
     * @param out         produce a reduced jpeg image if the image represented
     *                    by data is bigger than the maximum dimensions of the reduced
     *                    image, otherwise data is written to this stream
     */
    public static void createThumb(byte[] data,
                                   int thumbWidth, int thumbHeight,
                                   int quality,
                                   OutputStream out)
            throws Exception {
        Image image = Toolkit.getDefaultToolkit().createImage(data);
        MediaTracker mediaTracker = new MediaTracker(new Frame());
        int trackID = 0;
        mediaTracker.addImage(image, trackID);
        mediaTracker.waitForID(trackID);
        if (image.getWidth(null) <= thumbWidth &&
                image.getHeight(null) <= thumbHeight)
            out.write(data);
        else
            createThumb(image, thumbWidth, thumbHeight, quality, out);
    }

    /**
     * Create a scaled jpeg of an image. The width/height ratio is
     * preserved.
     * <p/>
     * <p>If image is smaller than thumbWidth x thumbHeight, it will be
     * magnified, otherwise it will be scaled down.</p>
     *
     * @param image       the image to reduce
     * @param thumbWidth  the maximum width of the thumbnail
     * @param thumbHeight the maximum heigth of the thumbnail
     * @param quality     the jpeg quality ot the thumbnail
     * @param out         a stream where the thumbnail data is written to
     */
    public static void createThumb(Image image,
                                   int thumbWidth, int thumbHeight,
                                   int quality,
                                   OutputStream out)
            throws Exception {
        int imageWidth = image.getWidth(null);
        int imageHeight = image.getHeight(null);
        double thumbRatio = (double) thumbWidth / (double) thumbHeight;
        double imageRatio = (double) imageWidth / (double) imageHeight;
        if (thumbRatio < imageRatio) {
            thumbHeight = (int) (thumbWidth / imageRatio);
        } else {
            thumbWidth = (int) (thumbHeight * imageRatio);
        }
        // draw original image to thumbnail image object and
        // scale it to the new size on-the-fly
        BufferedImage thumbImage =
                new BufferedImage(thumbWidth,
                        thumbHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2D = thumbImage.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);
        // save thumbnail image to out stream
        ImageIO.write(thumbImage, "jpeg", out);
    }

    public static byte[] getBytesFromFile(File file) throws IOException {
        InputStream is = new FileInputStream(file);

        // Get the size of the file
        long length = file.length();

        // You cannot create an array using a long type.
        // It needs to be an int type.
        // Before converting to an int type, check
        // to ensure that file is not larger than Integer.MAX_VALUE.
        if (length > Integer.MAX_VALUE) {
            // File is too large
        }

        // Create the byte array to hold the data
        byte[] bytes = new byte[(int) length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length
                && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
            offset += numRead;
        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }

        // Close the input stream and return bytes
        is.close();
        return bytes;
    }
}

